package com.guide.hello.curator;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

public class Main {
    private static final int BASE_SLEEP_TIME = 1000;
    private static final int MAX_RETRIES = 3;

    // 创建节点
    private static void create(CuratorFramework zkClient) {

        // a. 创建持久化节点
/*        try {
//            zkClient.create().forPath("/node1");
//            zkClient.create().forPath("/node1/00001");
            zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/node1/00001"); // creatingParentsIfNeeded可以保证父节点不存在的时候自动创建父节点
            zkClient.create().withMode(CreateMode.PERSISTENT).forPath("/node1/00002");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }*/

        // b. 创建临时节点：Java进程结束后，/node1/00001会自动消失，但/node1不会自动消失
/*        try {
            zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/node1/00001");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }*/

        // c. 创建节点并指定数据内容
        try {
            zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/node1/00001", "Java".getBytes());
            byte[] bytes = zkClient.getData().forPath("/node1/00001"); // 获取节点的数据内容，获取到的是byte数组
            String str = new String(bytes, StandardCharsets.UTF_8); // 使用UTF-8编码将字节数组转换为字符串
            System.out.println(str); // 输出: Java
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // d. 检测节点是否创建成功：不为null的话，说明节点创建成功
/*        try {
            if (zkClient.checkExists().forPath("/node1/00001") != null) {
                System.out.println("创建成功");
            } else {
                System.out.println("创建失败");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }*/
    }

    // 删除节点
    private static void delete(CuratorFramework zkClient) {
        // a. 删除一个子节点
        try {
            zkClient.delete().forPath("/node1/00001");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // b. 删除一个节点以及其下的所有子节点
        try {
            zkClient.delete().deletingChildrenIfNeeded().forPath("/node1");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 获取/更新节点数据内容
    private static void content(CuratorFramework zkClient) {
        String path = "/node1";
        try {
            if (zkClient.checkExists().forPath(path) == null) {
                zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/node1");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        try (PathChildrenCache pathChildrenCache = new PathChildrenCache(zkClient, path, true)) {
            PathChildrenCacheListener pathChildrenCacheListener = (curatorFramework, pathChildrenCacheEvent) -> {
                System.out.println(pathChildrenCacheEvent.getType());
            };
            pathChildrenCache.getListenable().addListener(pathChildrenCacheListener);
            pathChildrenCache.start(); // 注册子节点监听器

            zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/node1/00001", "Java".getBytes());
            zkClient.getData().forPath("/node1/00001");//获取节点的数据内容
            zkClient.setData().forPath("/node1/00001", "C++".getBytes());//更新节点数据内容
            byte[] bytes = zkClient.getData().forPath("/node1/00001");//获取节点的数据内容
            String str = new String(bytes, StandardCharsets.UTF_8); // 使用UTF-8编码将字节数组转换为字符串
            System.out.println(str); // 输出: C++

            // 等待足够的时间以观察事件（在生产代码中，应该使用更合适的机制来等待事件）
            TimeUnit.SECONDS.sleep(10);
            // 注意，由于使用了try-with-resources语句，最后会话断开子节点被删除的事件无法被监听到！
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        // Retry strategy. Retry 3 times, and will increase the sleep time between retries.
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(BASE_SLEEP_TIME, MAX_RETRIES);
        try (CuratorFramework zkClient = CuratorFrameworkFactory.builder()
                // the server to connect to (can be a server list)
                .connectString("127.0.0.1:2181")
                .retryPolicy(retryPolicy)
                .build()) {
            zkClient.start();

            // create(zkClient);
            // delete(zkClient);
            content(zkClient);
        }
    }
}
